#include "NaiveConvolution.h"


void naiveConvolution(const Mat_<uchar>& imgIn , Mat_<uchar>& imgOut, const Mat_<float>& kernel){

    // Kernel MUST be squared
    if(kernel.cols != kernel.rows) return;

    // Calculate half dim of kernel matrix (integer division)
    int k_aperture_size = kernel.cols/2;

    for(int r=k_aperture_size; r<imgIn.rows-k_aperture_size; ++r){
        for(int c=k_aperture_size; c<imgIn.cols-k_aperture_size; ++c){

			float sum = 0;

            for(int kr=0; kr<kernel.rows; ++kr){
                for(int kc=0; kc<kernel.cols; ++kc){
                    sum += imgIn(r+kr-k_aperture_size, c+kc-k_aperture_size) * kernel(kr,kc);
				}
			}

			imgOut(r,c) = sum;
        }
    }
}



void naiveConvWithPointers(uchar* imgIn , int img_rows, int img_cols, uchar* imgOut,
                           float* kernel, int kern_rows, int kern_cols){

    // Kernel MUST be squared
    if(kern_cols != kern_rows) return;

    // Calculate half dim of kernel matrix (integer division)
    int ksize = kern_cols/2;

    for(int r=ksize; r < img_rows - ksize; ++r){
        for(int c=ksize; c < img_cols - ksize; ++c){

			float sum = 0;

            int curr_px = r*img_cols+c;
            //Move inside the Kernel
            for(int kr=0; kr<kern_rows; ++kr)
                for(int kc=0; kc<kern_cols; ++kc){

                    float curr_kern_val = *(kernel + kr*kern_cols+kc);
                    int px_to_mult_with_krnl = *(imgIn + (r+kr-ksize)*img_cols +(c+kc-ksize));

                     sum += px_to_mult_with_krnl * curr_kern_val;
                }

			*(imgOut + curr_px) = sum;
        }
    }
}


void naiveConvWithPointers(Mat_<uchar> imgIn , Mat_<uchar>& imgOut,Mat_<float> kernel){

	naiveConvWithPointers(imgIn.data ,imgIn.rows, imgIn.cols, imgOut.data,(float*)kernel.data,kernel.rows,kernel.cols);

}

/*
int testNaiveConvolution(){

	//Immagine di ingresso
	Mat1b inImg = imread("lama.jpg",0);

	//Immagini di uscita
	Mat_<uchar> outImg3(inImg.rows,inImg.cols);
	Mat_<uchar> outImg4(inImg.rows,inImg.cols);

	//Kernel
	//Mat kernel = Mat::ones( 7, 7, CV_32F )/ (float)(7*7); //Kernel di media
	Mat_<float> kernel = getGaussianKernel(23,0.9f) * getGaussianKernel(23,0.9f).t(); //Kernel gaussiano
	
	//Timer
	clock_t startTime;

	namedWindow( "originale", CV_WINDOW_AUTOSIZE );
	imshow( "originale", inImg );
	
	//Naive Convolution
	startTime = clock();
	naiveConvolution(inImg, outImg3, kernel);
	cout << "naiveConvolution: "<< double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " secondi." << endl;

	namedWindow( "naive", CV_WINDOW_AUTOSIZE );
	imshow( "naive", outImg3 );

	//Naive Convolution con Puntatori
	startTime = clock();
	naiveConvWithPointers(inImg, outImg4, kernel);
	cout << "naiveConvWithPointers: "<< double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " secondi." << endl;
	
	namedWindow( "naivePointers", CV_WINDOW_AUTOSIZE );
	imshow( "naivePointers", outImg4 );

	waitKey();
	return 0;

}

*/
